package com.tsfyun.scm.config;

import cn.hutool.core.collection.CollectionUtil;
import com.tsfyun.common.base.annotation.DataScope;
import com.tsfyun.common.base.constant.DataScopeConstant;
import com.tsfyun.common.base.enums.LoginRoleTypeEnum;
import com.tsfyun.common.base.enums.PositionEnum;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.security.LoginVO;
import com.tsfyun.common.base.security.SecurityUtil;
import com.tsfyun.common.base.security.SysRoleVO;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.scm.entity.system.SysRole;
import com.tsfyun.scm.util.AuthUserUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static java.util.stream.Collectors.toList;

/**
 * 数据权限控制切面
 */
@RefreshScope
@Slf4j
@Aspect
@Component
public class DataScopeAspect {

    @Value("${scm.manage.person.code}")
    private String managePersonCode;

    @Value("${scm.manage.role.code}")
    private String manageRoleCode;

    //会在登录拦截器之后执行，此处不再做登录和在职状态（修改在职状态为离职会清空登录的信息）的判断了
    @Pointcut("@annotation(com.tsfyun.common.base.annotation.DataScope)")
    public void dataScopePointCut() {

    }
    //已同步 修改了职位/角色/在职状态登录信息的处理
    @Before("dataScopePointCut()")
    public void getDataSource(JoinPoint joinPoint) {
        DataScope dataScope = AnnotationUtils.getAnnotation(((MethodSignature)joinPoint.getSignature()).getMethod(), DataScope.class);
        if(Objects.isNull(dataScope)) {
            return;
        }
        Object params = joinPoint.getArgs()[0];
        if(Objects.nonNull(params) && params instanceof Map) {
            LoginVO loginVO = SecurityUtil.getCurrent();
            if(Objects.isNull(loginVO)) {
                throw new ServiceException("您还未登录，无权限访问");
            }
            wrapDataScopeSql((Map) params,loginVO,dataScope);
        }
    }

    public void wrapDataScopeSql(Map params,LoginVO loginVO,DataScope dataScope) {
        Map<String,String> scopeSqlMap = new HashMap<>();
        StringBuffer lastSql = new StringBuffer("");
        LoginRoleTypeEnum roleTypeEnum = LoginRoleTypeEnum.of(loginVO.getRoleType());
        if(Objects.equals(roleTypeEnum,LoginRoleTypeEnum.MANAGER)) {
            boolean isAdmin = AuthUserUtil.checkIsAdmin(loginVO.getSysRoles(),loginVO,manageRoleCode,managePersonCode);
            boolean allCustomer = false;
            if(isAdmin) {
                log.info("员工:{}是管理员或者角色是管理员组，不做数据权限控制",loginVO.getPersonName());
            }
            //如果是管理员则无需拼接数据权限SQL
            //关联客户表的inner sql片段
            StringBuffer dataInnerSql = new StringBuffer("");
            //客户查询条件的sql片段
            StringBuffer dataFilterSql1 = new StringBuffer("");
            //数据权限查询sql片段
            StringBuffer dataFilterSql2 = new StringBuffer("");
            //数据权限查询sql片段
            StringBuffer dataFilterSql3 = new StringBuffer("");

            //获取当前用户是否含有所有客户权限
            List<SysRoleVO> sysRoles = loginVO.getSysRoles();
            if(CollectionUtil.isNotEmpty(sysRoles)) {
                List<String> roleIds =  sysRoles.stream().map(SysRoleVO::getId).collect(toList());
                if(roleIds.contains(DataScopeConstant.ALL_CUSTOMER)) {
                    log.info("员工:{}的角色含有所有客户权限，不做数据权限控制",loginVO.getPersonName());
                    allCustomer = true;
                }
            }
            //业务表别名
            String tableAlias = dataScope.tableAlias();
            //客户表别名
            String customerTableAlias = dataScope.customerTableAlias();
            boolean relateCustomer = dataScope.relateCustomer();
            boolean addCustomerNameQuery = dataScope.addCustomerNameQuery();
            if(relateCustomer) {
                //如果是业务表关联的客户表，则2个表都需要设置别名
                if(StringUtils.isEmpty(tableAlias) || StringUtils.isEmpty(customerTableAlias)) {
                    throw new ServiceException("参数指定错误，请指定别名");
                }
                dataInnerSql.append(String.format(DataScopeConstant.INNER_CUSTOMER_SQL,customerTableAlias,customerTableAlias,tableAlias));
            }
            if(addCustomerNameQuery) {
                String customerName = StringUtils.null2EmptyWithTrim(params.get("customerName"));
                if(StringUtils.isNotEmpty(customerName)) {
                    if (StringUtils.isNotEmpty(customerTableAlias)) {
                        dataFilterSql1.append(customerTableAlias).append(".`name` like CONCAT('%', #{customerName}, '%') ");
                    } else {
                        dataFilterSql1.append(" `name` like CONCAT('%', #{customerName}, '%') ");
                    }
                }
            }
            //判断员工的岗位
            log.info("员工：{}当前岗位为:{}",loginVO.getPersonName(),loginVO.getPosition());
            PositionEnum positionEnum = PositionEnum.of(loginVO.getPosition());
            if(!isAdmin && !allCustomer) {//既不是管理员也没有全部客户权限，看岗位来判断
                if(Objects.nonNull(positionEnum)) {
                    switch (positionEnum) {
                        case BUSINESS:
                            //商务权限
                            if (StringUtils.isNotEmpty(customerTableAlias)) {
                                dataFilterSql2.append(String.format(" (%s.bus_person_id = %s or %s.bus_sec_person_id = %s)", customerTableAlias, loginVO.getPersonId(), customerTableAlias, loginVO.getPersonId()));
                            } else {
                                dataFilterSql2.append(String.format(" (bus_person_id = %s or bus_sec_person_id = %s )", loginVO.getPersonId(),loginVO.getPersonId()));
                            }
                            break;
                        case SALE:
                            //销售权限
                            if (StringUtils.isNotEmpty(customerTableAlias)) {
                                dataFilterSql2.append(String.format(" %s.sale_person_id = %s ", customerTableAlias, loginVO.getPersonId()));
                            } else {
                                dataFilterSql2.append(String.format(" sale_person_id = %s ", loginVO.getPersonId()));
                            }
                            break;
                        default:
                            //无权限
                            dataFilterSql2.append(" 0 = 1");
                            break;
                    }

                    //if(AuthUserUtil.checkIsUnknownCustomers(loginVO.getSysRoles())){
                    if (StringUtils.isNotEmpty(customerTableAlias)) {
                        dataFilterSql3.append(String.format(" or  %s.id = '0' ",customerTableAlias));
                    }else{
                        dataFilterSql3.append(" or id = '0' ");
                    }
                    //}
                } else {
                    //无权限
                    dataFilterSql2.append(" 0 = 1");
                }
            }
            scopeSqlMap.put(DataScopeConstant.SQL_INNER,dataInnerSql.toString());
            if(StringUtils.isNotEmpty(dataFilterSql1)) {
                lastSql.append(String.format(" AND ( %s ) ",dataFilterSql1.toString()));
            }
            if(StringUtils.isNotEmpty(dataFilterSql2)) {
                lastSql.append(String.format(" AND ( %s %s) ",dataFilterSql2.toString(),dataFilterSql3.toString()));
            }
        } else if (Objects.equals(roleTypeEnum,LoginRoleTypeEnum.CLIENT)) {
            //关联客户表的inner sql片段
            StringBuffer dataInnerSql = new StringBuffer("");
            //客户查询条件的sql片段
            StringBuffer dataFilterSql1 = new StringBuffer("");
            //数据权限查询sql片段
            StringBuffer dataFilterSql2 = new StringBuffer("");
            //业务表别名
            String tableAlias = dataScope.tableAlias();
            //客户表别名
            String customerTableAlias = dataScope.customerTableAlias();
            boolean relateCustomer = dataScope.relateCustomer();
            //客户端禁用关联客户名称查询，写死为false
            boolean addCustomerNameQuery = Boolean.FALSE;
            if(relateCustomer) {
                //如果是业务表关联的客户表，则2个表都需要设置别名
                if(StringUtils.isEmpty(tableAlias) || StringUtils.isEmpty(customerTableAlias)) {
                    throw new ServiceException("参数指定错误，请指定别名");
                }
                dataInnerSql.append(String.format(DataScopeConstant.INNER_CUSTOMER_SQL,customerTableAlias,customerTableAlias,tableAlias));
            }
            /*
            if(addCustomerNameQuery) {
                String customerName = StringUtils.null2EmptyWithTrim(params.get("customerName"));
                if(StringUtils.isNotEmpty(customerName)) {
                    if (StringUtils.isNotEmpty(customerTableAlias)) {
                        dataFilterSql1.append(customerTableAlias).append(".`name` like CONCAT('%', #{customerName}, '%') ");
                    } else {
                        dataFilterSql1.append(" `name` like CONCAT('%', #{customerName}, '%') ");
                    }
                }
            }
             */

            //添加客户id条件
            dataFilterSql2.append(String.format(DataScopeConstant.CUSTOMER_ID_SQL, tableAlias, loginVO.getCustomerId()));

            scopeSqlMap.put(DataScopeConstant.SQL_INNER,dataInnerSql.toString());
            if(StringUtils.isNotEmpty(dataFilterSql1)) {
                lastSql.append(String.format(" AND ( %s ) ",dataFilterSql1.toString()));
            }
            if(StringUtils.isNotEmpty(dataFilterSql2)) {
                lastSql.append(String.format(" AND ( %s ) ",dataFilterSql2.toString()));
            }

        } else if (Objects.equals(roleTypeEnum,LoginRoleTypeEnum.SALE)) {

        }
        scopeSqlMap.put(DataScopeConstant.SQL_FILTER,lastSql.toString());
        if(Objects.nonNull(scopeSqlMap)) {
            ((Map) params).putAll(scopeSqlMap);
        }
    }
}
